﻿using Sidvall.Serialization;
using System.Collections.Generic;
using System.Security.Principal;

namespace Sidvall.AuthorizationManager.Data
{
    public static class AuthorizationScopeItemManager
    {
        public const string ResourceSeparator = ",";
        public const string ResourceItemSeparator = "|";
        public const string ResourceItemActionSeparator = ".";
        public const string ActionSeparator = ",";
        public const string SubActionSeparator = ",";

        #region AddClaimsToPrincipal

        public static void AddClaimsToPrincipal(IPrincipal principal, IEnumerable<Sidvall.Security.Claim> claims, string claimType)
        {
            if (principal == null)
                return;
            if (Sidvall.SystemContext.Current.ClaimManager.HasClaim(principal.Identity, claimType, "1"))
                return;
            var claim = new Sidvall.Security.Claim()
            {
                ClaimType = claimType,
                Value = "1",
            };
            Sidvall.SystemContext.Current.ClaimManager.AddClaim(principal.Identity, claim);
            if (claims != null)
                Sidvall.SystemContext.Current.ClaimManager.AddClaims(principal.Identity, claims);
        }

        #endregion
        #region CreateNewFromJson

        public static AuthorizationScopeItem CreateNewFromJson(string json)
        {
            return Sidvall.Serialization.SerializerManager.Current.Serializer.Deserialize<AuthorizationScopeItem>(json);
        }

        #endregion
        #region CreateNewFromAuthorizationScope

        public static AuthorizationScopeItem CreateNewFromAuthorizationScope(IAuthorizationScope item, bool includeResourceItems, bool includeUserItems)
        {
            AuthorizationScopeItem applicationItem;

            if (item == null)
                return null;
            if (item.AuthorizationScopeId == null)
                return null;
            if (!item.IsEnabled)
                return null;
            applicationItem = new AuthorizationScopeItem();
            applicationItem.Load(item, includeResourceItems, includeUserItems);

            return applicationItem;
        }

        #endregion
        #region EnsureValid

        public static void EnsureValid(AuthorizationScopeItem item)
        {
            if (item.CacheResourceItemActions)
            {
                if (item.ResourceItemActions == null)
                    item.ResourceItemActions = new ResourceItemCollectionDictionary();
            }
            if (item.CacheUserItems)
            {
                if (item.UserItems == null)
                    item.UserItems = new Sidvall.Security.UserItemCollection();
            }
        }

        #endregion
        #region GetClaimItem

        public static ClaimItem GetClaimItem(IEnumerable<ClaimItem> items, string value)
        {
            if (items == null)
                return null;
            if (string.IsNullOrWhiteSpace(value))
            {
                foreach (var item in items)
                {
                    if (item.IsMatch(string.Empty))
                        return item;
                }
                return null;
            }
            else
            {
                value = value.Trim();
                foreach (var item in items)
                {
                    if (item.IsMatch(value))
                        return item;
                }
                return null;
            }
        }

        #endregion
        #region GetResourceItem

        public static ResourceItem GetResourceItem(IEnumerable<ResourceItem> items, string action, string subAction, bool filterResourceActionItems)
        {
            ResourceItem resourceItem;

            if (items == null)
                return null;
            if (string.IsNullOrWhiteSpace(action))
            {
                foreach (var item in items)
                {
                    if ((filterResourceActionItems) && (!item.ValidForResourceActionItems))
                        continue;
                    if (item.IsMatch(string.Empty, string.Empty))
                        return item;
                }
                return null;
            }
            else if (string.IsNullOrWhiteSpace(subAction))
            {
                resourceItem = null;
                action = action.Trim();
                foreach (var item in items)
                {
                    if ((filterResourceActionItems) && (!item.ValidForResourceActionItems))
                        continue;
                    if (item.IsMatch(action, string.Empty))
                        return item;
                    if (item.IsMatch(string.Empty, string.Empty))
                        resourceItem = item;
                }
                return resourceItem;
            }
            else
            {
                resourceItem = null;
                action = action.Trim();
                subAction = subAction.Trim();
                foreach (var item in items)
                {
                    if ((filterResourceActionItems) && (!item.ValidForResourceActionItems))
                        continue;
                    if (item.IsMatch(action, subAction))
                        return item;
                    if (item.IsMatch(action, string.Empty))
                        resourceItem = item;
                    if (resourceItem == null)
                    {
                        if (item.IsMatch(string.Empty, string.Empty))
                            resourceItem = item;
                    }
                }
                return resourceItem;
            }
        }

        #endregion
        #region GetResourceItems

        public static ResourceItemCollectionDictionary GetResourceItems(IEnumerable<IAuthorizationScopeResourceItem> items)
        {
            ResourceItemCollectionDictionary index;
            ResourceItemCollection resourceItems;
            string key;

            index = new ResourceItemCollectionDictionary();
            if (items != null)
            {
                foreach (var item in items)
                {
                    if (!item.IsEnabled)
                        continue;
                    if (string.IsNullOrWhiteSpace(item.Resource))
                        continue;
                    if (string.IsNullOrWhiteSpace(item.ResourceItemId))
                        continue;
                    key = item.Resource + ResourceItemSeparator + item.ResourceItemId;
                    if (!index.TryGetValue(key, out resourceItems))
                    {
                        resourceItems = new ResourceItemCollection();
                        index.Add(key, resourceItems);
                    }
                    resourceItems.Load(item.AccessLevel, ClaimManager.GetClaims(item.AuthorizationScopeResourceItemClaims), true, true, item.Actions, item.SubActions);
                }
            }
            return index;
        }
        public static ResourceItemCollectionDictionary GetResourceItems(IEnumerable<IAuthorizationScopeResourceAction> items)
        {
            ResourceItemCollectionDictionary index;
            string[] resources;

            index = new ResourceItemCollectionDictionary();
            if (items != null)
            {
                foreach (var item in items)
                {
                    if (!item.IsEnabled)
                        continue;
                    if (string.IsNullOrWhiteSpace(item.Resources))
                    {
                        Load(index, string.Empty, item);
                    }
                    else
                    {
                        resources = item.Resources.Split(AuthorizationScopeItemManager.ResourceSeparator);
                        foreach (var resource in resources)
                            Load(index, resource.Trim(), item);
                    }
                }
            }
            return index;
        }
        private static void Load(ResourceItemCollectionDictionary index, string resource, IAuthorizationScopeResourceAction item)
        {
            ResourceItemCollection resourceItems;

            if (!index.TryGetValue(resource, out resourceItems))
            {
                resourceItems = new ResourceItemCollection();
                index.Add(resource, resourceItems);
            }
            if (!string.IsNullOrWhiteSpace(resource))
                resourceItems.Load(item.AccessLevel, ClaimManager.GetClaims(item.AuthorizationScopeResourceActionClaims), true, item.ValidForResourceActionItems, item.Actions, item.SubActions);
            else
                resourceItems.Load(item.AccessLevel, ClaimManager.GetClaims(item.AuthorizationScopeResourceActionClaims), false, item.ValidForResourceActionItems, item.Actions, item.SubActions);
        }

        #endregion

        #region LoadResourceItems

        public static void LoadResourceItems(Sidvall.Security.ResourceItemCollection items, string resource, IEnumerable<ResourceItem> resourceItems, IPrincipal principal, bool userIsValid)
        {
            if (items == null)
                return;
            if (resourceItems == null)
                return;
            foreach (var resourceItem in resourceItems)
            {
                var item = new Sidvall.Security.ResourceItem()
                {
                    Action = resourceItem.Action,
                    Resource = resource,
                    SubAction = resourceItem.SubAction,
                };
                if (resourceItem.IsAuthorized(principal, userIsValid, item))
                    items.Add(item);
            }
        }

        #endregion
    }
}
